<!DOCTYPE html>



  


<html class="theme-next mist use-motion" lang="zh-Hans">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />







<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.1.4" rel="stylesheet" type="text/css" />


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png?v=5.1.4">


  <link rel="mask-icon" href="/images/logo.svg?v=5.1.4" color="#222">





  <meta name="keywords" content="Hexo, NexT" />










<meta property="og:type" content="website">
<meta property="og:title" content="kyssion-blog">
<meta property="og:url" content="http://yoursite.com/page/12/index.html">
<meta property="og:site_name" content="kyssion-blog">
<meta property="og:locale" content="zh-Hans">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="kyssion-blog">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Mist',
    version: '5.1.4',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://yoursite.com/page/12/"/>





  <title>kyssion-blog</title>
  








</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  
  
    
  

  <div class="container sidebar-position-left 
  page-home">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">kyssion-blog</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle"></p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-about">
          <a href="/about/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-user"></i> <br />
            
            关于
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
            
            标签
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            归档
          </a>
        </li>
      
        
        <li class="menu-item menu-item-schedule">
          <a href="/schedule/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-calendar"></i> <br />
            
            日程表
          </a>
        </li>
      
        
        <li class="menu-item menu-item-sitemap">
          <a href="/sitemap.xml" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-sitemap"></i> <br />
            
            站点地图
          </a>
        </li>
      
        
        <li class="menu-item menu-item-commonweal">
          <a href="/404/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-heartbeat"></i> <br />
            
            公益404
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            
  <section id="posts" class="posts-expand">
    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/10/09/docker（一）基础/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kyssion">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="kyssion-blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/10/09/docker（一）基础/" itemprop="url">未命名</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-10-09T15:22:37+08:00">
                2018-10-09
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <p>docker 不多说就是拥有独立的存储空间的更加优秀的类虚拟机系统，他拥有许多优秀的思想，比如吸收了git的存储仓库的思想，使用image参照git中的仓库等。</p>
<h3 id="docker-之分层存储"><a href="#docker-之分层存储" class="headerlink" title="docker 之分层存储"></a>docker 之分层存储</h3><p>Docker 设计时，就充分利用 Union FS 的技术，将其设计为分层存储的架构。所以严格来说，镜像并非是像一个 ISO 那样的打包文件，镜像只是一个虚拟的概念，其实际体现并非由一个文件组成，而是由一组文件系统组成，或者说，由多层文件系统联合组成。</p>
<p>镜像构建时，会一层层构建，前一层是后一层的基础。每一层构建完就不会再发生改变，后一层上的任何改变只发生在自己这一层。比如，删除前一层文件的操作，实际不是真的删除前一层的文件，而是仅在当前层标记为该文件已删除。在最终容器运行的时候，虽然不会看到这个文件，但是实际上该文件会一直跟随镜像。因此，在构建镜像的时候，需要额外小心，每一层尽量只包含该层需要添加的东西，任何额外的东西应该在该层构建结束前清理掉。</p>
<p>分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层，然后进一步添加新的层，以定制自己所需的内容，构建新的镜像。</p>
<h3 id="docker-之容器"><a href="#docker-之容器" class="headerlink" title="docker 之容器"></a>docker 之容器</h3><p>镜像（Image）和容器（Container）的关系，就像是面向对象程序设计中的 类 和 实例 一样，镜像是静态的定义，容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。</p>
<p>容器的实质是进程，但与直接在宿主执行的进程不同，容器进程运行于属于自己的独立的 命名空间。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间，甚至自己的用户 ID 空间。容器内的进程是运行在一个隔离的环境里，使用起来，就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。也因为这种隔离的特性，很多人初学 Docker 时常常会混淆容器和虚拟机。</p>
<p>前面讲过镜像使用的是分层存储，容器也是如此。每一个容器运行时，是以镜像为基础层，在其上创建一个当前容器的存储层，我们可以称这个为容器运行时读写而准备的存储层为容器存储层。</p>
<p>容器存储层的生存周期和容器一样，容器消亡时，容器存储层也随之消亡。因此，任何保存于容器存储层的信息都会随容器删除而丢失。</p>
<p>按照 Docker 最佳实践的要求，容器不应该向其存储层内写入任何数据，容器存储层要保持无状态化。所有的文件写入操作，都应该使用 数据卷（Volume）、或者绑定宿主目录，在这些位置的读写会跳过容器存储层，直接对宿主（或网络存储）发生读写，其性能和稳定性更高。</p>
<p>数据卷的生存周期独立于容器，容器消亡，数据卷不会消亡。因此，使用数据卷后，容器删除或者重新运行之后，数据却不会丢失。</p>
<h3 id="docker-之仓库"><a href="#docker-之仓库" class="headerlink" title="docker 之仓库"></a>docker 之仓库</h3><p>docker仓库的功能和git仓库类似这里就不展开说明了，这里主要讨论一下docker仓库特殊的命名规则。</p>
<p>以 Ubuntu 镜像 为例，ubuntu 是仓库的名字，其内包含有不同的版本标签，如，14.04, 16.04。我们可以通过 ubuntu:14.04，或者 ubuntu:16.04 来具体指定所需哪个版本的镜像。如果忽略了标签，比如 ubuntu，那将视为 ubuntu:latest。</p>
<p>仓库名经常以 两段式路径 形式出现，比如 jwilder/nginx-proxy，前者往往意味着 Docker Registry 多用户环境下的用户名，后者则往往是对应的软件名。但这并非绝对，取决于所使用的具体 Docker Registry 的软件或服务。</p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/10/09/dubbo学习和使用（五）dubbo功能（3）/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kyssion">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="kyssion-blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/10/09/dubbo学习和使用（五）dubbo功能（3）/" itemprop="url">未命名</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-10-09T15:22:37+08:00">
                2018-10-09
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h2 id="参数回调"><a href="#参数回调" class="headerlink" title="参数回调"></a>参数回调</h2><blockquote>
<p>参数回调方式与调用本地 callback 或 listener 相同，只需要在 Spring 的配置文件中声明哪个参数是 callback 类型即可。Dubbo 将基于长连接生成反向代理，这样就可以从服务器端调用客户端逻辑。</p>
</blockquote>
<blockquote>
<p>服务接口示例</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line">CallbackService.java</span><br><span class="line"><span class="keyword">package</span> com.callback;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">CallbackService</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">addListener</span><span class="params">(String key, CallbackListener listener)</span></span>;</span><br><span class="line">&#125;</span><br><span class="line">CallbackListener.java</span><br><span class="line"><span class="keyword">package</span> com.callback;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">CallbackListener</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">changed</span><span class="params">(String msg)</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&gt; 服务提供者接口实现示例</span><br><span class="line"></span><br><span class="line">```java</span><br><span class="line"><span class="keyword">package</span> com.callback.impl;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">import</span> java.text.SimpleDateFormat;</span><br><span class="line"><span class="keyword">import</span> java.util.Date;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.ConcurrentHashMap;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">import</span> com.callback.CallbackListener;</span><br><span class="line"><span class="keyword">import</span> com.callback.CallbackService;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CallbackServiceImpl</span> <span class="keyword">implements</span> <span class="title">CallbackService</span> </span>&#123;</span><br><span class="line">     </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Map&lt;String, CallbackListener&gt; listeners = <span class="keyword">new</span> ConcurrentHashMap&lt;String, CallbackListener&gt;();</span><br><span class="line">  </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">CallbackServiceImpl</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        Thread t = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">            <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                <span class="keyword">while</span>(<span class="keyword">true</span>) &#123;</span><br><span class="line">                    <span class="keyword">try</span> &#123;</span><br><span class="line">                        <span class="keyword">for</span>(Map.Entry&lt;String, CallbackListener&gt; entry : listeners.entrySet())&#123;</span><br><span class="line">                           <span class="keyword">try</span> &#123;</span><br><span class="line">                               entry.getValue().changed(getChanged(entry.getKey()));</span><br><span class="line">                           &#125; <span class="keyword">catch</span> (Throwable t) &#123;</span><br><span class="line">                               listeners.remove(entry.getKey());</span><br><span class="line">                           &#125;</span><br><span class="line">                        &#125;</span><br><span class="line">                        Thread.sleep(<span class="number">5000</span>); <span class="comment">// 定时触发变更通知</span></span><br><span class="line">                    &#125; <span class="keyword">catch</span> (Throwable t) &#123; <span class="comment">// 防御容错</span></span><br><span class="line">                        t.printStackTrace();</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        t.setDaemon(<span class="keyword">true</span>);</span><br><span class="line">        t.start();</span><br><span class="line">    &#125;</span><br><span class="line">  </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">addListener</span><span class="params">(String key, CallbackListener listener)</span> </span>&#123;</span><br><span class="line">        listeners.put(key, listener);</span><br><span class="line">        listener.changed(getChanged(key)); <span class="comment">// 发送变更通知</span></span><br><span class="line">    &#125;</span><br><span class="line">     </span><br><span class="line">    <span class="function"><span class="keyword">private</span> String <span class="title">getChanged</span><span class="params">(String key)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"Changed: "</span> + <span class="keyword">new</span> SimpleDateFormat(<span class="string">"yyyy-MM-dd HH:mm:ss"</span>).format(<span class="keyword">new</span> Date());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>服务提供者配置示例</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"callbackService"</span> <span class="attr">class</span>=<span class="string">"com.callback.impl.CallbackServiceImpl"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"com.callback.CallbackService"</span> <span class="attr">ref</span>=<span class="string">"callbackService"</span> <span class="attr">connections</span>=<span class="string">"1"</span> <span class="attr">callbacks</span>=<span class="string">"1000"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:method</span> <span class="attr">name</span>=<span class="string">"addListener"</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dubbo:argument</span> <span class="attr">index</span>=<span class="string">"1"</span> <span class="attr">callback</span>=<span class="string">"true"</span> /&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--也可以通过指定类型的方式--&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--&lt;dubbo:argument type="com.demo.CallbackListener" callback="true" /&gt;--&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dubbo:method</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dubbo:service</span>&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>服务消费者配置示例</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">id</span>=<span class="string">"callbackService"</span> <span class="attr">interface</span>=<span class="string">"com.callback.CallbackService"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>服务消费者调用示例</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">ClassPathXmlApplicationContext context = <span class="keyword">new</span> ClassPathXmlApplicationContext(<span class="string">"classpath:consumer.xml"</span>);</span><br><span class="line">context.start();</span><br><span class="line"> </span><br><span class="line">CallbackService callbackService = (CallbackService) context.getBean(<span class="string">"callbackService"</span>);</span><br><span class="line"> </span><br><span class="line">callbackService.addListener(<span class="string">"http://10.20.160.198/wiki/display/dubbo/foo.bar"</span>, <span class="keyword">new</span> CallbackListener()&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">changed</span><span class="params">(String msg)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"callback1:"</span> + msg);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure>
<h2 id="事件通知"><a href="#事件通知" class="headerlink" title="事件通知"></a>事件通知</h2><p>在调用之前、调用之后、出现异常时，会触发 oninvoke、onreturn、onthrow 三个事件，可以配置当事件发生时，通知哪个类的哪个方法。</p>
<p>服务提供者与消费者共享服务接口</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">IDemoService</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> Person <span class="title">get</span><span class="params">(<span class="keyword">int</span> id)</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>服务提供者实现</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">NormalDemoService</span> <span class="keyword">implements</span> <span class="title">IDemoService</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> Person <span class="title">get</span><span class="params">(<span class="keyword">int</span> id)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> Person(id, <span class="string">"charles`son"</span>, <span class="number">4</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>服务提供者配置</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:application</span> <span class="attr">name</span>=<span class="string">"rpc-callback-demo"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:registry</span> <span class="attr">address</span>=<span class="string">"http://10.20.160.198/wiki/display/dubbo/10.20.153.186"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"demoService"</span> <span class="attr">class</span>=<span class="string">"com.alibaba.dubbo.callback.implicit.NormalDemoService"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"com.alibaba.dubbo.callback.implicit.IDemoService"</span> <span class="attr">ref</span>=<span class="string">"demoService"</span> <span class="attr">version</span>=<span class="string">"1.0.0"</span> <span class="attr">group</span>=<span class="string">"cn"</span>/&gt;</span></span><br></pre></td></tr></table></figure>
<p>服务消费者 Callback 接口</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Notify</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onreturn</span><span class="params">(Person msg, Integer id)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onthrow</span><span class="params">(Throwable ex, Integer id)</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>服务消费者 Callback 实现</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">NotifyImpl</span> <span class="keyword">implements</span> <span class="title">Notify</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> Map&lt;Integer, Person&gt;    ret    = <span class="keyword">new</span> HashMap&lt;Integer, Person&gt;();</span><br><span class="line">    <span class="keyword">public</span> Map&lt;Integer, Throwable&gt; errors = <span class="keyword">new</span> HashMap&lt;Integer, Throwable&gt;();</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onreturn</span><span class="params">(Person msg, Integer id)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"onreturn:"</span> + msg);</span><br><span class="line">        ret.put(id, msg);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onthrow</span><span class="params">(Throwable ex, Integer id)</span> </span>&#123;</span><br><span class="line">        errors.put(id, ex);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>服务消费者 Callback 配置</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span> =<span class="string">"demoCallback"</span> <span class="attr">class</span> = <span class="string">"com.alibaba.dubbo.callback.implicit.NofifyImpl"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">id</span>=<span class="string">"demoService"</span> <span class="attr">interface</span>=<span class="string">"com.alibaba.dubbo.callback.implicit.IDemoService"</span> <span class="attr">version</span>=<span class="string">"1.0.0"</span> <span class="attr">group</span>=<span class="string">"cn"</span> &gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">dubbo:method</span> <span class="attr">name</span>=<span class="string">"get"</span> <span class="attr">async</span>=<span class="string">"true"</span> <span class="attr">onreturn</span> = <span class="string">"demoCallback.onreturn"</span> <span class="attr">onthrow</span>=<span class="string">"demoCallback.onthrow"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dubbo:reference</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>callback 与 async 功能正交分解，async=true 表示结果是否马上返回，onreturn 表示是否需要回调。</p>
<p>两者叠加存在以下几种组合情况 [2]：</p>
<ul>
<li>异步回调模式：async=true onreturn=”xxx”</li>
<li>同步回调模式：async=false onreturn=”xxx”</li>
<li>异步无回调 ：async=true</li>
<li>同步无回调 ：async=false</li>
</ul>
<p>测试代码</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">IDemoService demoService = (IDemoService) context.getBean(<span class="string">"demoService"</span>);</span><br><span class="line">NofifyImpl notify = (NofifyImpl) context.getBean(<span class="string">"demoCallback"</span>);</span><br><span class="line"><span class="keyword">int</span> requestId = <span class="number">2</span>;</span><br><span class="line">Person ret = demoService.get(requestId);</span><br><span class="line">Assert.assertEquals(<span class="keyword">null</span>, ret);</span><br><span class="line"><span class="comment">//for Test：只是用来说明callback正常被调用，业务具体实现自行决定.</span></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">    <span class="keyword">if</span> (!notify.ret.containsKey(requestId)) &#123;</span><br><span class="line">        Thread.sleep(<span class="number">200</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">Assert.assertEquals(requestId, notify.ret.get(requestId).getId());</span><br></pre></td></tr></table></figure>
<h2 id="本地存根"><a href="#本地存根" class="headerlink" title="本地存根"></a>本地存根</h2><blockquote>
<p>远程服务后，客户端通常只剩下接口，而实现全在服务器端，但提供方有些时候想在客户端也执行部分逻辑，比如：做 ThreadLocal 缓存，提前验证参数，调用失败后伪造容错数据等等，此时就需要在 API 中带上 Stub，客户端生成 Proxy 实例，会把 Proxy 通过构造函数传给 Stub，然后把 Stub 暴露给用户，Stub 可以决定要不要去调 Proxy。</p>
</blockquote>
<p><img src="blogimg/dubbo/n9.png" alt=""></p>
<p>在 spring 配置文件中按以下方式配置：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">stub</span>=<span class="string">"true"</span> /&gt;</span></span><br><span class="line">或者</span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">stub</span>=<span class="string">"com.foo.BarServiceStub"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<p>提供 Stub 的实现：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.foo;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BarServiceStub</span> <span class="keyword">implements</span> <span class="title">BarService</span> </span>&#123; </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> BarService barService;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 构造函数传入真正的远程代理对象</span></span><br><span class="line">    <span class="keyword">public</span> (BarService barService) &#123;</span><br><span class="line">        <span class="keyword">this</span>.barService = barService;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">sayHello</span><span class="params">(String name)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 此代码在客户端执行, 你可以在客户端做ThreadLocal本地缓存，或预先验证参数是否合法，等等</span></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> barService.sayHello(name);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            <span class="comment">// 你可以容错，可以做任何AOP拦截事项</span></span><br><span class="line">            <span class="keyword">return</span> <span class="string">"容错数据"</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ol>
<li><p>Stub 必须有可传入 Proxy 的构造函数。</p>
</li>
<li><p>在 interface 旁边放一个 Stub 实现，它实现 BarService 接口，并有一个传入远程 BarService 实例的构造函数</p>
</li>
</ol>
<h2 id="本地伪装"><a href="#本地伪装" class="headerlink" title="本地伪装"></a>本地伪装</h2><p>本地伪装通常用于服务降级，比如某验权服务，当服务提供方全部挂掉后，客户端不抛出异常，而是通过 Mock 数据返回授权失败。</p>
<p>在 spring 配置文件中按以下方式配置：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">mock</span>=<span class="string">"true"</span> /&gt;</span></span><br><span class="line">或</span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">mock</span>=<span class="string">"com.foo.BarServiceMock"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<p>在工程中提供 Mock 实现：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.foo;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BarServiceMock</span> <span class="keyword">implements</span> <span class="title">BarService</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">sayHello</span><span class="params">(String name)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 你可以伪造容错数据，此方法只在出现RpcException时被执行</span></span><br><span class="line">        <span class="keyword">return</span> <span class="string">"容错数据"</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>如果服务的消费方经常需要 try-catch 捕获异常，如</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">Offer offer = <span class="keyword">null</span>;</span><br><span class="line"><span class="keyword">try</span> &#123;</span><br><span class="line">    offer = offerService.findOffer(offerId);</span><br><span class="line">&#125; <span class="keyword">catch</span> (RpcException e) &#123;</span><br><span class="line">   logger.error(e);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>请考虑改为 Mock 实现，并在 Mock 实现中 return null。如果只是想简单的忽略异常，在 2.0.11 以上版本可用</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">mock</span>=<span class="string">"return null"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<ul>
<li><p>Mock 是 Stub 的一个子集，便于服务提供方在客户端执行容错逻辑，因经常需要在出现 RpcException (比如网络失败，超时等)时进行容错，而在出现业务异常(比如登录用户名密码错误)时不需要容错，如果用 Stub，可能就需要捕获并依赖 RpcException 类，而用 Mock 就可以不依赖 RpcException，因为它的约定就是只有出现 RpcException 时才执行。</p>
</li>
<li><p>在 interface 旁放一个 Mock 实现，它实现 BarService 接口，并有一个无参构造函数</p>
</li>
</ul>
<h2 id="延迟暴露"><a href="#延迟暴露" class="headerlink" title="延迟暴露"></a>延迟暴露</h2><p>如果你的服务需要预热时间，比如初始化缓存，等待相关资源就位等，可以使用 delay 进行延迟暴露。</p>
<p>延迟 5 秒暴露服务</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">delay</span>=<span class="string">"5000"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<p>延迟到 Spring 初始化完成后，再暴露服务 [1]</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">delay</span>=<span class="string">"-1"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>注意：Spring 2.x 初始化死锁问题</p>
</blockquote>
<p>原因描述<br>在 Spring 解析到 &lt;dubbo:service /&gt; 时，就已经向外暴露了服务，而 Spring 还在接着初始化其它 Bean。如果这时有请求进来，并且服务的实现类里有调用 applicationContext.getBean() 的用法。</p>
<ol>
<li><p>请求线程的 applicationContext.getBean() 调用，先同步 singletonObjects 判断 Bean 是否存在，不存在就同步 beanDefinitionMap 进行初始化，并再次同步 singletonObjects 写入 Bean 实例缓存。</p>
</li>
<li><p>而 Spring 初始化线程，因不需要判断 Bean 的存在，直接同步 beanDefinitionMap 进行初始化，并同步 singletonObjects 写入 Bean 实例缓存。</p>
</li>
</ol>
<p>这样就导致 getBean 线程，先锁 singletonObjects，再锁 beanDefinitionMap，再次锁 singletonObjects。<br>而 Spring 初始化线程，先锁 beanDefinitionMap，再锁 singletonObjects。反向锁导致线程死锁，不能提供服务，启动不了。</p>
<h2 id="并发控制"><a href="#并发控制" class="headerlink" title="并发控制"></a>并发控制</h2><p>配置样例</p>
<blockquote>
<p>样例 1</p>
</blockquote>
<p>限制 com.foo.BarService 的每个方法，服务器端并发执行（或占用线程池线程数）不能超过 10 个：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">executes</span>=<span class="string">"10"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>样例 2</p>
</blockquote>
<p>限制 com.foo.BarService 的 sayHello 方法，服务器端并发执行（或占用线程池线程数）不能超过 10 个：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:method</span> <span class="attr">name</span>=<span class="string">"sayHello"</span> <span class="attr">executes</span>=<span class="string">"10"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dubbo:service</span>&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>样例 3</p>
</blockquote>
<p>限制 com.foo.BarService 的每个方法，每客户端并发执行（或占用连接的请求数）不能超过 10 个：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">actives</span>=<span class="string">"10"</span> /&gt;</span></span><br><span class="line">或</span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">actives</span>=<span class="string">"10"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>样例 4</p>
</blockquote>
<p>限制 com.foo.BarService 的 sayHello 方法，每客户端并发执行（或占用连接的请求数）不能超过 10 个：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:method</span> <span class="attr">name</span>=<span class="string">"sayHello"</span> <span class="attr">actives</span>=<span class="string">"10"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dubbo:service</span>&gt;</span></span><br><span class="line">或</span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:method</span> <span class="attr">name</span>=<span class="string">"sayHello"</span> <span class="attr">actives</span>=<span class="string">"10"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dubbo:service</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>注意：如果 \<a href="dubbo:service" target="_blank" rel="noopener">dubbo:service</a> 和 \<a href="dubbo:reference" target="_blank" rel="noopener">dubbo:reference</a> 都配了actives，\<a href="dubbo:reference" target="_blank" rel="noopener">dubbo:reference</a> 优先，参见：配置的覆盖策略。</p>
<blockquote>
<p>Load Balance 均衡</p>
</blockquote>
<p>配置服务的客户端的 loadbalance 属性为 leastactive，此 Loadbalance 会调用并发数最小的 Provider（Consumer端并发数）。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">loadbalance</span>=<span class="string">"leastactive"</span> /&gt;</span></span><br><span class="line">或</span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">loadbalance</span>=<span class="string">"leastactive"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<h2 id="连接控制"><a href="#连接控制" class="headerlink" title="连接控制"></a>连接控制</h2><blockquote>
<p>服务端连接控制</p>
</blockquote>
<p>限制服务器端接受的连接不能超过 10 个：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:provider</span> <span class="attr">protocol</span>=<span class="string">"dubbo"</span> <span class="attr">accepts</span>=<span class="string">"10"</span> /&gt;</span></span><br><span class="line">或</span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:protocol</span> <span class="attr">name</span>=<span class="string">"dubbo"</span> <span class="attr">accepts</span>=<span class="string">"10"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>客户端连接控制</p>
</blockquote>
<p>限制客户端服务使用连接不能超过 10 个：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">connections</span>=<span class="string">"10"</span> /&gt;</span></span><br><span class="line">或</span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">connections</span>=<span class="string">"10"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<p>如果 \<a href="dubbo:service" target="_blank" rel="noopener">dubbo:service</a> 和 \<a href="dubbo:reference" target="_blank" rel="noopener">dubbo:reference</a> 都配了 connections，\<a href="dubbo:reference" target="_blank" rel="noopener">dubbo:reference</a> 优先</p>
<h2 id="延迟连接"><a href="#延迟连接" class="headerlink" title="延迟连接"></a>延迟连接</h2><p>延迟连接用于减少长连接数。当有调用发起时，再创建长连接.</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:protocol</span> <span class="attr">name</span>=<span class="string">"dubbo"</span> <span class="attr">lazy</span>=<span class="string">"true"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<h2 id="粘滞连接"><a href="#粘滞连接" class="headerlink" title="粘滞连接"></a>粘滞连接</h2><p>粘滞连接用于有状态服务，尽可能让客户端总是向同一提供者发起调用，除非该提供者挂了，再连另一台。</p>
<p>粘滞连接将自动开启延迟连接，以减少长连接数。<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:protocol</span> <span class="attr">name</span>=<span class="string">"dubbo"</span> <span class="attr">sticky</span>=<span class="string">"true"</span> /&gt;</span></span><br></pre></td></tr></table></figure></p>
<h2 id="令牌验证"><a href="#令牌验证" class="headerlink" title="令牌验证"></a>令牌验证</h2><p>通过令牌验证在注册中心控制权限，以决定要不要下发令牌给消费者，可以防止消费者绕过注册中心访问提供者，另外通过注册中心可灵活改变授权方式，而不需修改或升级提供者</p>
<p><img src="blogimg/dubbo/n10.png" alt=""></p>
<p>可以全局设置开启令牌验证：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--随机token令牌，使用UUID生成--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:provider</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">token</span>=<span class="string">"true"</span> /&gt;</span></span><br><span class="line"><span class="comment">&lt;!--固定token令牌，相当于密码--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:provider</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">token</span>=<span class="string">"123456"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>也可在服务级别设置：</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--随机token令牌，使用UUID生成--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">token</span>=<span class="string">"true"</span> /&gt;</span></span><br><span class="line"><span class="comment">&lt;!--固定token令牌，相当于密码--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">token</span>=<span class="string">"123456"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>还可在协议级别设置：</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--随机token令牌，使用UUID生成--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:protocol</span> <span class="attr">name</span>=<span class="string">"dubbo"</span> <span class="attr">token</span>=<span class="string">"true"</span> /&gt;</span></span><br><span class="line"><span class="comment">&lt;!--固定token令牌，相当于密码--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:protocol</span> <span class="attr">name</span>=<span class="string">"dubbo"</span> <span class="attr">token</span>=<span class="string">"123456"</span> /&gt;</span></span><br></pre></td></tr></table></figure>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/10/09/blogimg/maven 实战笔记 （二）maven常用插件/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kyssion">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="kyssion-blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/10/09/blogimg/maven 实战笔记 （二）maven常用插件/" itemprop="url">未命名</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-10-09T15:22:37+08:00">
                2018-10-09
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            
          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/10/09/GoF设计模式（四）Factory Method/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kyssion">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="kyssion-blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/10/09/GoF设计模式（四）Factory Method/" itemprop="url">未命名</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-10-09T15:22:37+08:00">
                2018-10-09
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h3 id="工厂方法模式"><a href="#工厂方法模式" class="headerlink" title="工厂方法模式"></a>工厂方法模式</h3><p>这个模式之前的时候感觉比较困难，现在感觉这个模式同样是比较简单的，要注意一下的几个思想。</p>
<ol>
<li>工厂方法模式一开始的时候是将工厂接口和工厂生产的产品同时定义出来的。</li>
<li>工厂生产的东西需要传入指定的数据才能生产出来比如下面例子中定义的IDcard类</li>
</ol>
<blockquote>
<p>扩展思路&gt; 其实感觉这个模式其实可以和模板方法模式结合使用，在构建产品的过程中使用模板方法模式可以进一步的解耦和优化流程。</p>
</blockquote>
<h3 id="工厂方法模式的类图"><a href="#工厂方法模式的类图" class="headerlink" title="工厂方法模式的类图"></a>工厂方法模式的类图</h3><p><img src="blogimg/GAF/5.png" alt=""></p>
<p>从类图中可以看出项目中工厂和产品之间的关系</p>
<h3 id="工厂方法模式例子"><a href="#工厂方法模式例子" class="headerlink" title="工厂方法模式例子"></a>工厂方法模式例子</h3><h4 id="接口"><a href="#接口" class="headerlink" title="接口"></a>接口</h4><ol>
<li>工厂接口</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.kys.Gaf.FactoryMethod;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Factory</span></span>&#123;</span><br><span class="line">     <span class="function">Product <span class="title">create</span><span class="params">(IDcard iDcard)</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ol start="2">
<li>产品接口</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.kys.Gaf.FactoryMethod;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Product</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">use</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="接口的实现类"><a href="#接口的实现类" class="headerlink" title="接口的实现类"></a>接口的实现类</h4><ol>
<li>工厂的实现类</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.kys.Gaf.FactoryMethod;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BookProduct</span> <span class="keyword">implements</span> <span class="title">Product</span></span>&#123;</span><br><span class="line">    IDcard iDcard;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">BookProduct</span><span class="params">(IDcard iDcard)</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.iDcard=iDcard;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">use</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(iDcard.getName()+<span class="string">"正在使用：\""</span>+iDcard.getCardName()+<span class="string">"\"ID 卡"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ol start="2">
<li>商品的实现类</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.kys.Gaf.FactoryMethod;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BookProduct</span> <span class="keyword">implements</span> <span class="title">Product</span></span>&#123;</span><br><span class="line">    IDcard iDcard;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">BookProduct</span><span class="params">(IDcard iDcard)</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.iDcard=iDcard;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">use</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(iDcard.getName()+<span class="string">"正在使用：\""</span>+iDcard.getCardName()+<span class="string">"\"ID 卡"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="信息载体"><a href="#信息载体" class="headerlink" title="信息载体"></a>信息载体</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.kys.Gaf.FactoryMethod;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">IDcard</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> String cardName;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">IDcard</span><span class="params">(String cardName,String name)</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.cardName=cardName;</span><br><span class="line">        <span class="keyword">this</span>.name=name;</span><br><span class="line">        System.out.println(<span class="string">"创建了"</span>+<span class="keyword">this</span>.getName()+<span class="string">"的"</span>+<span class="keyword">this</span>.getCardName()+<span class="string">"卡片"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getCardName</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> cardName;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setCardName</span><span class="params">(String cardName)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.cardName = cardName;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="运行主函数"><a href="#运行主函数" class="headerlink" title="运行主函数"></a>运行主函数</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.kys.Gaf.FactoryMethod;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Factory factory = <span class="keyword">new</span> BookFactory();</span><br><span class="line">        Product product1= factory.create(<span class="keyword">new</span> IDcard(<span class="string">"美容卡"</span>,<span class="string">"tom"</span>));</span><br><span class="line">        Product product2= factory.create(<span class="keyword">new</span> IDcard(<span class="string">"购物卡"</span>,<span class="string">"jack"</span>));</span><br><span class="line">        product1.use();</span><br><span class="line">        product2.use();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/10/09/Groovy学习使用（一）/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kyssion">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="kyssion-blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/10/09/Groovy学习使用（一）/" itemprop="url">未命名</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-10-09T15:22:37+08:00">
                2018-10-09
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            
          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/10/09/Serverless（baas & faas）无服务器计算/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kyssion">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="kyssion-blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/10/09/Serverless（baas & faas）无服务器计算/" itemprop="url">未命名</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-10-09T15:22:37+08:00">
                2018-10-09
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <blockquote>
<p>自从2014年AWS推出Lambda服务后，Serverless一词越来越热，已经成为一种新型的软件设计架构，即Serverless Architecture。作为一种原生于公共云的架构，Serverless有什么优缺点？是否能应用于传统企业程序？是否适合私有云场景？是否像很多文章宣称的一样，会成为未来改变云计算的中坚力量？作为一名云计算行业的老兵，作者想在此文中分享一些自己的观点。</p>
</blockquote>
<h3 id="什么是Serverless"><a href="#什么是Serverless" class="headerlink" title="什么是Serverless"></a>什么是Serverless</h3><p>Serverless并不神秘，用一个简单的例子就可讲明。我们设计了一个AI应用，可以识别出图片中人物的人种，我们把它作为一种SaaS服务架设在公共云上提供给客户使用，其典型的后端架构设计如下：</p>
<p><img src="/blogimg/serverless/serverless_img1.jpeg" alt=""></p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;在该架构中，我们购买的云主机上运行了Tomcat Web Server，用于承载Java编写的AI应用。用户通过API上传图片。受限于云主机的本地存储空间，为了满足大量客户同时上传图片，AI应用实现了一个存储网关将图片导入公共云的对象存储。图片导入完成后，AI应用从对象存储读入图片进行识别，并将结果存入公共云的数据库中（例如RDS），用户使用API查询结果。<br>&nbsp; &nbsp;&nbsp; &nbsp;AI应用上线一段时间后受到了用户的欢迎，越来越多的公司开始使用该服务。根据统计数据，大多数公司在上午9点~11点、下午2点~5点集中上传图片，为了满足该时间段的突发访问量，我们设置了公共云的&nbsp; &nbsp;&nbsp; &nbsp;Auto-Scaling策略，在访问增加时动态创建更多的云主机来响应客户。AI应用的架构演化成：</p>
<ul>
<li>在这个架构中，我们需要做如下事情：</li>
</ul>
<ol>
<li>管理云主机。我们要关心CPU数量、内存大小、IP地址等等系统级的配置。同时还要关心云主机的操作系统，为部署AI应用拟定策略。操作系统和Tomcat的安全补丁也不能忽视，否则竞争对手可能雇佣黑客来攻击我们的系统。</li>
<li>配置公共云的Auto-Scaling的策略，应对高峰期突发访问量。</li>
<li>使用公共云的对象存储和数据库。</li>
<li>编写AI应用。<br>&nbsp; &nbsp;&nbsp; &nbsp;要完成这些工作，我们既要开发AI应用，又要营运支撑业务（例如管理云主机生命周期、管理操作系统）。这是当前架构的现实：为20%的核心业务营运80%的支撑业务。</li>
</ol>
<ul>
<li>下面用Serverless架构改写AI应用：</li>
</ul>
<p><img src="/blogimg/serverless/servless_img2.jpeg" alt=""></p>
<ul>
<li><p>多个运行AI应用代码的进程被启动，并发处理用户上传的图片。</p>
</li>
<li><p>在Serverless架构的AI应用中，我们只需要做两件事情：</p>
</li>
</ul>
<ol>
<li><p>使用公共云的对象存储和数据库。</p>
</li>
<li><p>用公共云的Serverless框架编写AI应用。</p>
</li>
</ol>
<p>&nbsp; &nbsp;&nbsp; &nbsp;与之前的架构相比，我们不再营运云主机、操作系统、Tomcat，同时也不需要配置Auto-Scaling Group，公共云的Serverless框架会在每个图片上传完成后启动一个进程运行AI应用，自动实现水平扩展。我们终于只需要关心核心业务了，用Serverless框架支持的语言（例如AWS Lambda就支持Java, Python和JVM系语言）编写AI应用，一切非核心业务都外包给了公共云营运商。</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;我们的Serverless AI应用用到了两种技术。首先使用了公共云提供的对象存储和数据库服务，统称为BaaS（Backend as a Service，后端即服务）。其次用了Lambda框架，称为FaaS(Functions as a Service，函数即服务)。</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;使用BaaS和FaaS是Serverless应用的基本特征，符合这两个基本特征的应用可称为Serverless应用。</p>
<h3 id="是BaaS，不是PaaS"><a href="#是BaaS，不是PaaS" class="headerlink" title="是BaaS，不是PaaS"></a>是BaaS，不是PaaS</h3><p>&nbsp; &nbsp;&nbsp; &nbsp;AI应用用到了对象存储和数据库，将来或许还会用到消息队列。直观感觉是在使用PaaS，为什么还要造一个新词BaaS？技术圈有太多令人混淆的术语了。</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;BaaS并非PaaS，它们的区别在于：PaaS需要参与应用的生命周期管理，BaaS则仅仅提供应用依赖的第三方服务。典型的PaaS平台需要提供手段让开发者部署和配置应用，例如自动将应用部署到Tomcat容器中，并管理应用的生命周期。BaaS不包含这些内容，BaaS只以API的方式提供应用依赖的后端服务，例如数据库和对象存储。BaaS可以是公共云服务商提供的，也可以是第三方厂商提供的，例如Facebook收购的Parse就是著名的MBaaS提供商（Mobile Backend as a Service）。从功能上讲，BaaS可以看作PaaS的一个子集，即提供第三方依赖组件的部分。</p>
<h3 id="FaaS是Serverless的核心"><a href="#FaaS是Serverless的核心" class="headerlink" title="FaaS是Serverless的核心"></a>FaaS是Serverless的核心</h3><p>&nbsp; &nbsp;&nbsp; &nbsp;AI应用最初是一个典型Java程序，它可能使用Spring这样的技术，因为我们需要一个框架确保程序的各个组件能够被正确加载，需要MVC来保证REST API被正确的Controller处理。AI应用部署在Tomcat容器中，运行在云主机上，7 x 24小时运行，我们提供不间断的服务。在夜里12点到早晨8点，几乎没有用户使用，但我们还得让它待在那里，防止深夜偶尔使用的用户得到一个503错误而误会AI服务不稳定。我们为购买的云主机付钱，尽管一半的时间它的CPU使用率几乎为0，但没有公共云是按CPU使用率计费的，不工作的时间也得付钱。我们必须关心Auto-Scaling Group的配置，如何准确的配置Auto-Scaling策略是一个技术活，需要长期的经验积累，在早期我们不得不多部署一些空闲的云主机以保证服务不会因Auto-Scaling的配置不当而拥塞。</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;用Serverless架构改写了AI应用后，这些痛苦就通通消失了。Spring框架和Tomcat去掉了，用Lambda的Java SDK，只需要实现一个Function Handler处理图片上传完成这个事件，这跟写一个Callback一样简单。在Function Handler中调用图片识别的相关逻辑，然后调用数据库的REST API存储结果。也不用构建MVC，不用配置Tomcat的XML文件，我们将存储网关这个功能完全去除掉了，因为用户可以直接上传图片到对象存储。</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;AI应用不用7 x 24小时运行了，没有用户上传图片时它只是一份编译好的代码。当用户图片上传完成时，FaaS会为AI应用启动一个新的进程执行代码。该进程在代码执行完成后自动销毁。我们只需为代码执行的这几十秒钟付钱，节省了很多开支。</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;最后我们无需操心Auto-Scaling的问题，FaaS会在需要的时候自动扩展。</p>
<ul>
<li>这些就是FaaS的核心，从上面的例子里面可以归纳出它的特点：</li>
</ul>
<ol>
<li><p>FaaS运行的是后端代码而不是整个后端程序。例如AI应用仅仅包含处理图片上传完成这个事件的逻辑，并不是一个完整的后端程序，而是一段后端代码。</p>
</li>
<li><p>代码通过事件触发。由于不再有一个长期运行的进程等待或轮询用户请求，代码只能通过特殊的事件触发。这些事件由FaaS框架定义，例如上传文件到对象存储、消息队列收到一条新的消息、API Gateway收到一个新的API请求等。</p>
</li>
<li><p>代码的生命周期很短。例如我们的AI应用，从收到事件后Function Handler被调用开始，到调用返回结束，不会有常驻内存的进程运行。此外公共云提供商还会限制代码执行的时间，超出时间后执行代码的进程会被强行销毁。例如AWS的Lambda可执行的最长时间为5分钟。</p>
</li>
<li><p>代码必须做到彻底无状态，两次调用间不能共享内存状态。我们的AI应用最早使用了一个全局变量统计处理的图片数，每处理完一张图片该计数器就加一。使用FaaS后我们不能再用任何全局变量或内存数据结构（例如Hashmap）在调用间共享数据，因为代码运行在独立的进程中，无法访问对方的内存地址空间。于是我们对代码进行了改造，将全局计数器放到了公共云的Redis服务中，这为代码增加了额外的复杂性。</p>
</li>
<li><p>水平扩展不再是需要担心的问题，FaaS会为每个事件和请求运行一份新的代码。</p>
</li>
<li><p>应用的部署方式从上传、配置整个程序变成上传一份打包代码的文件（例如Jar文件或一个Zip文件）。</p>
</li>
</ol>
<h3 id="Serverless为我们带来了什么"><a href="#Serverless为我们带来了什么" class="headerlink" title="Serverless为我们带来了什么"></a>Serverless为我们带来了什么</h3><p>&nbsp; &nbsp;&nbsp; &nbsp;对比传统架构，用Serverless架构改写的AI应用具有显著的优势。我们不再运维任何云主机和操作系统，甚至不再运维Tomcat这样的Web容器，只需要专注于代码本身，所有配置、应用生命周期管理的工作都由FaaS框架负责。公共云的出现让我们从物理硬件管理中解放出来，Serverless架构让我们进一步从操作系统管理中解放出来，第一次真正专注于核心业务。</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;业务也变得更加敏捷了。我们只需要编写核心业务相关的代码，例如AI应用中图像识别的部分。无需编写任何加载、部署、配置应用的代码，例如不再需要配置systemd在系统启动时加载应用。</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;水平扩展也不是问题。正如前面反复提及的，FaaS框架会为每一个事件、每一个API请求都启动一份新的进程执行代码。这跟传统应用的线程池方式类似，每个请求都在一个单独的线程中执行，区别在于线程之间共享同一内存地址空间，FaaS的进程间不共享任何内存。与线程池有最大线程数限制类似，FaaS框架通常也限制了最大进程数，例如AWS Lambda在一个Region默认能执行的最大并发调用是600，也就是说我们的AI应用最多能在600个进程中同时执行。</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;最后，也是最重要的，Serverless架构为我们节省了大量开支。我们只需为AI应用运行的时间付钱，无需为应用等待请求的时间付钱。水平扩展的粒度从原来的云主机细化到进程，节省了额外的开支，不用再购买闲置的云主机来抵消Auto-Scaling的配置不精确带来的影响。业务的敏捷性提高也降低了营运成本，我们不再需要精通操作系统配置和管理的营运人员，不仅节省了人力成本，也节省了应用从开发到上线的时间。</p>
<h3 id="Serverless不是银子弹，是后端小程序的未来"><a href="#Serverless不是银子弹，是后端小程序的未来" class="headerlink" title="Serverless不是银子弹，是后端小程序的未来"></a>Serverless不是银子弹，是后端小程序的未来</h3><p>&nbsp; &nbsp;&nbsp; &nbsp;serverless架构在某些应用场景的优势如此明显，有些支持者已经开始炒作它会成为颠覆性的云计算新架构了。技术圈向来如此，一些人总在孜孜不倦的寻找包治百病的灵药，和解决一切问题的银子弹。“All design is about tradeoff”，Serverless也不是银子弹，它有独特的优势，而这些优势也带来了不可避免的局限。</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;为每个事件/请求启动一个全新的进程运行代码是FaaS的核心，进程的启动延时是Serverless面临的第一个问题。取决于编写应用的语言，启动延时可以是10毫秒（如简单的Python应用），也可以是1分钟（复杂的Java应用）。这样的延时对于realtime的程序是难以接受的。目前Serverless应用通常运行在公共云的多租户环境中，启动延时还受系统负载影响，很难保证应用在规定时间内被运行。公共云提供商目前没有对Serverless提供相应的SLA保证，笔者写这篇文章的时候，AWS Lambda还没有相关的SLA条款。</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;Serverless无法用于高并发应用，为每个请求启动一个进程开销太高。例如双十一支付宝高峰期每秒处理的交易数为8.59万笔，如果使用Serverless架构，意味着我们的系统内每秒有8.59万个进程被创建又被销毁，这是难以负担的开销。</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;Serverless应用无法常驻内存，运行的时间是受限的。如果你的应用无法在数分钟内完成的工作，那Serverless不是你的选择，例如AWS Lambda给予进程的最长运行时间是5分钟，超时后进程将被强制终止。这对程序设计提出了挑战，例如我们的AI应用必须优化到在5分钟内完成复杂图像的识别。我们也不能编写执行长时间IO操作的应用，例如对对象存储中1T的数据进行复杂编码。</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;Serverless调用之间不能共享状态让编写复杂程序变得极度困难。无状态是互连网应用追求的目标，例如满足“12要素”的应用。但Serverless将无状态进行的更加彻底，在不同的调用之间无法共享内存状态，例如使用hashmap。我们的AI应用中统计已处理图片总数的全局计数器在传统架构中只是一个全局变量，但在Serverless架构中它变成存储在内存数据库（Redis）中的一条记录，更新成本、保证原子性等因素让我们的编码变得数倍复杂。对于大多云原生的互联网应用来说，这种彻底的无状态架构是一个巨大的挑战，而对于动辄有几十万、上百万行代码的、充满了状态的企业应用来说，Serverless的无状态改造几乎是一个无法完成的任务。</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;熟练的微服务的架构师，对将业务拆分成一个个单独的服务非常熟悉，也有不少的经典书籍（例如《Building Microservices: Designing Fine-Grained Systems》）指导我们如何做。但即使是他们，在面对Serverless架构时也会感到头痛，如何将业务拆分成成百上千个运行在独立进程、运行时间受限的函数是巨大的挑战。而是否需要如此细粒度的拆分是需要回答的第一个问题。有些问题或许变成无解难题又或成本极高，例如分布式数据库事务。</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;上面都是Serverless架构的一些固有局限，它们源于Serverless架构的特点，很难随着时间的推移、技术的完善而解决。除此之外，作为一个新的技术，Serverless还面临着集成测试困难、Vendor Lock-in、调试监控困难、版本控制等诸多不足，每一项都会成为采用Serverless架构的阻碍。</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;由于这些局限性，Serverless架构不会成为复杂应用的架构首选，相反，它应该是后端小程序的未来。</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;云端的应用有大量的小程序场景，例如识别一张图片、对一段音频/视频进行编解码、对IOT设备的请求返回一小段数据、将客户提交的工单通过邮件通知客服人员等等。这些基于事件触发的小程序在传统架构中实现起来是相对复杂的，你往往需要为20%的核心业务运营80%的支撑业务。Serverless完美的解决了这些问题，它可以成为复杂应用的一种补充架构。我们可以将无状态的、事件触发的业务拆分成Serverless应用，让整个架构变得更加的简洁和高效。</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;Serverless也在不断演变，例如AWS最近引入的Step Functions就尝试解决调用间共享状态的问题，其效果有待观察。</p>
<h3 id="Serverless不是传统的PaaS"><a href="#Serverless不是传统的PaaS" class="headerlink" title="Serverless不是传统的PaaS"></a>Serverless不是传统的PaaS</h3><p>&nbsp; &nbsp;&nbsp; &nbsp;Serverless跟PaaS之间的界线比较模糊，很多人认为Serverless是PaaS的一种，笔者也倾向于认为Serverless是特殊的PaaS形态。</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;Serverless由BaaS和FaaS两部分构成，BaaS负责提供业务的依赖服务，FaaS负责业务的部署和生命周期管理，从这个意义上来看，Serverless的角色跟PaaS一样。与传统PaaS的区别在于，传统PaaS是以程序为粒度管理应用的生命周期，而Serverless是以函数粒度管理应用生命周期。传统PaaS中的应用为常驻内存的进程，而Serverless应用运行完即销毁。此外，使用传统PaaS，用户仍需要关心水平扩展，例如如何配置Auto-Scaling Group，但Serverless没有这个问题，水平扩展是架构天然自带的功能。</p>
<h3 id="Serverless和微服务"><a href="#Serverless和微服务" class="headerlink" title="Serverless和微服务"></a>Serverless和微服务</h3><p>&nbsp; &nbsp;&nbsp; &nbsp;Serverless和微服务没有直接关系，但两者有相似之处，例如都需要做业务拆分、强调无状态、具有敏捷特性等。Serverless在很多方面比微服务粒度更细，要求也更严格。例如微服务以服务为边界拆分业务，Serverless以函数为边界拆分业务；微服务可以有跨调用的内存状态共享，Serverless要求调用彻底无状态。此外，Serverless依赖BaaS提供第三方依赖，而微服务可以自由选择第三方依赖来源，例如使用本地搭建的传统中间件栈（如本地MySql和消息总线）。</p>
<h3 id="Serverless和容器"><a href="#Serverless和容器" class="headerlink" title="Serverless和容器"></a>Serverless和容器</h3><p>&nbsp; &nbsp;&nbsp; &nbsp;Serverless和容器是苹果和桔子的比较，不在一个平面上。Serverless是一种软件设计架构，容器是软件架构的承载者。虽然没有公开资料，但我们可以推测类似于AWS Lambda这样的Serverless框架使用了某种程度的容器技术，否者难以实现语言无关和毫秒级的启动。尽管已经有一些开源项目使用Docker实现Serverless中的FaaS部分，笔者不认为AWS Lambda这样的公共Serverless框架直接使用了Docker，一定是一种更为轻量级、体积更小的容器技术，我们或许可以将它称为Nano-Container。</p>
<h3 id="Serverless对私有云有意义吗？"><a href="#Serverless对私有云有意义吗？" class="headerlink" title="Serverless对私有云有意义吗？"></a>Serverless对私有云有意义吗？</h3><p>&nbsp; &nbsp;&nbsp; &nbsp;对于私有云来说，现在将业务迁往Serverless架构还为时过早。首先Serverless是从公共云中演化出来的新型架构，适用于运行在公共云上的小程序。而私有云更多承载的是老而笨重的传统业务，难以用Serverless架构改造。其次Serverless依赖BaaS，在私有云中搭建和运维BaaS成本都不低，使用公共BaaS服务又受限于网络带宽和延时，容易导致系统不稳定。</p>
<p>&nbsp; &nbsp;&nbsp; &nbsp;随着企业应用的进一步云化、开源Serverless框架的成熟，私有云的Devops场景也可以采用Serverless作CI/CD，例如目前Jenkins承担的大部分工作都可以用Serverless替代，如用FaaS框架对应Jenkins本身，上传的代码对应Jenkins Job中的Bash脚本，将原来的Jenkins API触发Job改为触发FaaS中的代码。</p>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>&nbsp; &nbsp;&nbsp; &nbsp;Serverless作为一种全新的架构，是云计算发展演化的必然结果。追求更细粒度的计费单元，更加专注于核心业务、将支撑业务外包给基础设施提供商是云计算的趋势。Serverless架构的特点，让编写事件触发的后端小程序变得更加容易。同时它也有自身内在的局限性，并不适合复杂的应用架构。从目前的情况看，部分采用Serverless的混合架构对公共云应用是个不错的选择，私有应用采用Serverless还为时过早。云计算技术正在飞速发展，未来还有无限可能。</p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/10/09/Java-范型/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kyssion">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="kyssion-blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/10/09/Java-范型/" itemprop="url">未命名</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-10-09T15:22:37+08:00">
                2018-10-09
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h3 id="一-定义范型"><a href="#一-定义范型" class="headerlink" title="一.定义范型"></a>一.定义范型</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">A</span>&lt;<span class="title">T</span>&gt; </span>&#123;&#125;</span><br></pre></td></tr></table></figure>
<h4 id="1-范型可以使用有界表示法"><a href="#1-范型可以使用有界表示法" class="headerlink" title="(1)范型可以使用有界表示法"></a>(1)范型可以使用有界表示法</h4><p><strong>extends</strong> 表示下界<br><strong>surper</strong> 表示上界<br><strong>class B <t extends="" a="">{}</t></strong> # 表示只有A或者A的子类可接受<br><strong>class C<t super="" f="">{}</t></strong> # 表示只有F或者是F的父类可接受</p>
<blockquote>
<p>注意 ：范型中的T不能进行强制转化—静态编译型语言特点</p>
</blockquote>
<h4 id="2-范型通配符"><a href="#2-范型通配符" class="headerlink" title="(2)范型通配符 ?"></a>(2)范型通配符 ?</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//点是集合类型使用通配符的时候见下面的例子</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Other</span></span>&#123;</span><br><span class="line">	<span class="comment">//?通配符表示一般的匹配相关的有嗯来约束一类的类型</span></span><br><span class="line">	<span class="class"><span class="keyword">class</span> <span class="title">Rong</span>&lt;<span class="title">T</span>&gt;</span>&#123;</span><br><span class="line">		</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="class"><span class="keyword">class</span> <span class="title">One</span></span>&#123;&#125;</span><br><span class="line">	<span class="class"><span class="keyword">class</span> <span class="title">Two</span> <span class="keyword">extends</span> <span class="title">One</span></span>&#123;&#125;</span><br><span class="line">	<span class="class"><span class="keyword">class</span> <span class="title">Three</span> <span class="keyword">extends</span> <span class="title">Two</span></span>&#123;&#125;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">methodone</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		Rong&lt;? extends Two&gt; rong = <span class="keyword">new</span> Rong&lt;Three&gt;();</span><br><span class="line">		<span class="comment">//Rong&lt;? extends Two&gt; rong2 = new Rong&lt;One&gt;();//报错了因为不满足上界</span></span><br><span class="line">		Rong&lt; ? <span class="keyword">super</span> Two&gt; rong3 = <span class="keyword">new</span> Rong&lt;One&gt;();</span><br><span class="line">		<span class="comment">//---注意--- 集合类型的通配符模式下 	extends只能取不能存取得是extends后面的类型  </span></span><br><span class="line">		<span class="comment">//								surper 只能存变量强制转化成Object类型不能取</span></span><br><span class="line">		List&lt;? extends Two&gt; list=<span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">		One one= list.get(<span class="number">0</span>);</span><br><span class="line">		Two two = list.get(<span class="number">0</span>);<span class="comment">//因为extends表示存的类型都是Two的子类但是添加的时候只能加入一种类型，所以只能取不能存 super反之</span></span><br><span class="line">		<span class="comment">//list.set(0, new Three());//报错</span></span><br><span class="line">		List&lt;? <span class="keyword">super</span> Two&gt; list2 = <span class="keyword">new</span> ArrayList&lt;&gt;();</span><br><span class="line">		list2.add(<span class="keyword">new</span> Three());<span class="comment">//适因为内部一定知道相关 术语上转型</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="三-继承中的范型"><a href="#三-继承中的范型" class="headerlink" title="三.继承中的范型"></a>三.继承中的范型</h3><blockquote>
<p>只要保证外部的范型类型必须实现内部的</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">ThisisT</span>&lt;<span class="title">T</span> <span class="keyword">extends</span> <span class="title">Father</span>,<span class="title">V</span>&gt;</span>&#123;</span><br><span class="line">	<span class="comment">//注意泛型不能是基本类型只能是引用类型  但是java 的自定装箱机制会将基本类型变成引用类型</span></span><br><span class="line">	<span class="comment">//因为引用类型 不能是基本类型 意味着 声明 泛型的时候不能使用引用类型</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="title">ThisisT</span><span class="params">(T heh)</span> </span>&#123;&#125;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="title">ThisisT</span><span class="params">(V v)</span></span>&#123;&#125;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="title">ThisisT</span><span class="params">(T t,V v)</span></span>&#123;</span><br><span class="line">		<span class="comment">//</span></span><br><span class="line">		t.thisisFatherMehthod();</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">//? 通配符  其实和T所带表的意义是是相同的 但是 ? 通配符是为了解决   函数 内部的方法调用 泛型类的时候所采用的因为泛型类中不能使用除了已经声明的泛型之外的字母</span></span><br><span class="line">	<span class="comment">//其余的 T等是一样的方法</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">method</span><span class="params">(ArrayList&lt;?&gt; arrayList)</span></span>&#123;<span class="comment">//这样这个方法就能接受除了T V 类型之外的其他类型</span></span><br><span class="line">		</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Father</span></span>&#123;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">thisisFatherMehthod</span><span class="params">()</span></span>&#123;&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Mother</span>&lt;<span class="title">T</span> <span class="keyword">extends</span> <span class="title">ArrayList</span>&lt;<span class="title">T</span>&gt;&gt;</span>&#123;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">ThisisMatherMethod</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//--继承或者 实现的接口 终不能写extends等语句  具体的实现需要在新的类名称中写 官方属于叫做声明值的传递</span></span><br><span class="line"><span class="comment">//继承泛型类  ---</span></span><br><span class="line"><span class="class"><span class="keyword">class</span>  <span class="title">Ceshi</span>&lt;<span class="title">T</span> <span class="keyword">extends</span> <span class="title">ArrayList</span>&lt;<span class="title">T</span>&gt;&gt; <span class="keyword">implements</span> <span class="title">Mother</span>&lt;<span class="title">T</span>&gt;</span>&#123;</span><br><span class="line"> </span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">ThisisMatherMethod</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="comment">// TODO Auto-generated method stub</span></span><br><span class="line">		</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//继承泛型接口</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Ceshi2</span>&lt;<span class="title">T</span> <span class="keyword">extends</span> <span class="title">Father</span>, <span class="title">V</span>&gt; <span class="keyword">extends</span> <span class="title">ThisisT</span>&lt;<span class="title">T</span>,<span class="title">V</span>&gt;</span>&#123;</span><br><span class="line"> </span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="title">Ceshi2</span><span class="params">(T heh)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">super</span>(heh);</span><br><span class="line">		<span class="comment">// TODO Auto-generated constructor stub</span></span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//继承泛型类外加泛型接口</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Ceshi3</span>&lt;<span class="title">M</span> <span class="keyword">extends</span> <span class="title">ArrayList</span>&lt;<span class="title">M</span>&gt;, <span class="title">V</span>, <span class="title">T</span> <span class="keyword">extends</span> <span class="title">Father</span>&gt; <span class="keyword">extends</span> <span class="title">ThisisT</span>&lt;<span class="title">T</span>,<span class="title">V</span>&gt; <span class="keyword">implements</span> <span class="title">Mother</span>&lt;<span class="title">M</span>&gt;</span>&#123;</span><br><span class="line"> </span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="title">Ceshi3</span><span class="params">(T heh)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">super</span>(heh);</span><br><span class="line">		<span class="comment">// TODO Auto-generated constructor stub</span></span><br><span class="line">	&#125;</span><br><span class="line"> </span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">ThisisMatherMethod</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="comment">// TODO Auto-generated method stub</span></span><br><span class="line">		</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">BBB</span>&lt;<span class="title">T</span>&gt;</span>&#123;</span><br><span class="line">	<span class="function"><span class="keyword">public</span> T <span class="title">say</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">AAA</span> <span class="keyword">extends</span> <span class="title">BBB</span>&lt;<span class="title">Integer</span>&gt;</span>&#123;<span class="comment">//范型继承可以是已知的类型使用使用已知了型可以在前面不加上属性，但是如果前面加上属性将导致后面的类型变成未知</span></span><br><span class="line">	<span class="meta">@Override</span></span><br><span class="line">	<span class="function"><span class="keyword">public</span> Integer <span class="title">say</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="comment">// TODO Auto-generated method stub</span></span><br><span class="line">		<span class="keyword">return</span> <span class="number">123</span>;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="四-范型的底层实现"><a href="#四-范型的底层实现" class="headerlink" title="四.范型的底层实现"></a>四.范型的底层实现</h3><p>为了实现与非泛型代码的兼容，Java语言的泛型采用<strong>擦除(Erasure)</strong>来实现，也就是泛型基本上由编译器来实现，由编译器执行类型检查和类型推断，然后在生成字节码之前将其清<strong>除掉</strong>，虚拟机是不知道泛型存在的。这样的话，泛型和非泛型的代码就可以混合运行，当然了，也显得相当混乱。</p>
<p>在使用泛型时，会有一个对应的类型叫做原生类型(raw<br>type)，泛型类型会被擦除到原生类型，如Generic<t>会被查处到Generic，<strong>List<string></string></strong>会被查处到List，由于擦除，在虚拟机中无法获得任何类型信息，虚拟机只知道原生类型。下面的代码将展示Java泛型的真相–擦除：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Erasure</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line">	<span class="keyword">private</span> T t;</span><br><span class="line">	</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">set</span><span class="params">(T t)</span> </span>&#123;</span><br><span class="line">		<span class="keyword">this</span>.t = t;</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	<span class="function"><span class="keyword">public</span> T <span class="title">get</span><span class="params">()</span> </span>&#123;</span><br><span class="line">		<span class="keyword">return</span> t;</span><br><span class="line">	&#125;</span><br><span class="line">	</span><br><span class="line">	<span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;	</span><br><span class="line">		Erasure&lt;String&gt; eras = <span class="keyword">new</span> Erasure&lt;String&gt;();</span><br><span class="line">		eras.set(<span class="string">"not real class type"</span>);</span><br><span class="line">		String value = eras.get();</span><br><span class="line">		</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></t></p>
<p>使用javap反编译class文件，得到如下代码：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">com</span>.<span class="title">think</span>.<span class="title">generics</span>.<span class="title">Erasure</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line">  com.think.generics.Erasure();</span><br><span class="line">    Code:</span><br><span class="line">       <span class="number">0</span>: aload_0       </span><br><span class="line">       1: invokespecial #12                 // Method java/lang/Object."&lt;init&gt;":()V</span><br><span class="line">       <span class="number">4</span>: <span class="keyword">return</span>        </span><br><span class="line"> </span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">set</span><span class="params">(T)</span></span>;</span><br><span class="line">    Code:</span><br><span class="line">       <span class="number">0</span>: aload_0       </span><br><span class="line">       <span class="number">1</span>: aload_1       </span><br><span class="line">       2: putfield      #23                 // Field t:Ljava/lang/Object;</span><br><span class="line">       <span class="number">5</span>: <span class="keyword">return</span>        </span><br><span class="line"> </span><br><span class="line">  <span class="function"><span class="keyword">public</span> T <span class="title">get</span><span class="params">()</span></span>;</span><br><span class="line">    Code:</span><br><span class="line">       <span class="number">0</span>: aload_0       </span><br><span class="line">       1: getfield      #23                 // Field t:Ljava/lang/Object;</span><br><span class="line">       <span class="number">4</span>: areturn       </span><br><span class="line"> </span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(java.lang.String[])</span></span>;</span><br><span class="line">    Code:</span><br><span class="line">       0: new           #1                  // class com/think/generics/Erasure</span><br><span class="line">       <span class="number">3</span>: dup           </span><br><span class="line">       4: invokespecial #30                 // Method "&lt;init&gt;":()V</span><br><span class="line">       <span class="number">7</span>: astore_1      </span><br><span class="line">       <span class="number">8</span>: aload_1       </span><br><span class="line">       9: ldc           #31                 // String not real class type</span><br><span class="line">      11: invokevirtual #33                 // Method set:(Ljava/lang/Object;)V</span><br><span class="line">      <span class="number">14</span>: aload_1       </span><br><span class="line">      15: invokevirtual #35                 // Method get:()Ljava/lang/Object;</span><br><span class="line">      18: checkcast     #37                 // class java/lang/String</span><br><span class="line">      <span class="number">21</span>: astore_2      </span><br><span class="line">      <span class="number">22</span>: <span class="keyword">return</span>        </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>从反编译出来的字节码可以看到，泛型Erasure<t>被擦除到了Erasure，其内部的字段T被擦除到了Object，可以看到get和set方法中都是把t作为Object来使用的。最值得关注的是，反编译代码的倒数第三行，对应到Java代码就是String<br>value =<br>eras.get();编译器执行了类型转换。这就是Java泛型的本质：对传递进来的值进行额外的编译期检查，并插入对传递出去的值的转型。这样的泛型真的是泛型吗？</t></p>
<p>即便我们可以说，Java中的泛型确实不是真正的泛型，但是它带来的好处还是显而易见的，它使得Java的类型安全前进了一大步，原本需要程序员显式控制的类型转换，现在改由编译器来实现，只要你按照泛型的规范去编写代码，总会得到安全的保障。在这里，我们不得不思考一个问题，理解Java泛型，那么其核心目的是什么？我个人认为，Java泛型的核心目的在于安全性，尤其是在理解泛型通配符时，一切奇怪的规则，归根结底都是处于安全的目的。</p>
<p><strong>类型信息的丢失</strong></p>
<p>由于擦除的原因，在泛型代码内部，无法获得任何有关泛型参数类型的信息。在运行时，虚拟机无法获得确切的类型信息，一切以来确切类型信息的工作都无法完成，比如instanceof操作，和new表达式，<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span>  <span class="title">Erasure</span>&lt;<span class="title">T</span>&gt;  </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">f</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(arg <span class="keyword">instanceof</span> T) <span class="comment">//Error</span></span><br><span class="line">        T ins = <span class="keyword">new</span> T();<span class="comment">//Error</span></span><br><span class="line">        T[] array = <span class="keyword">new</span> T[<span class="number">10</span>];<span class="comment">//error</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">那么在需要具体的类型信息时，我们就要记住Class对象来实现了，凡是在运行时需要类型信息的地方，都使用Class对象来进行操作，比如：</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Erasure</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> Class&lt;T&gt; clazz;</span><br><span class="line">    Erasure(Class&lt;T&gt; kind) &#123;</span><br><span class="line">        clazz = kind;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">f</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(clazz.isInstance(arg)) &#123;&#125;</span><br><span class="line">        T t = clazz.newInstance();<span class="comment">//必须要有无参构造方法</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h3 id="五-型的相关坑点"><a href="#五-型的相关坑点" class="headerlink" title="五.型的相关坑点"></a>五.型的相关坑点</h3><ul>
<li><strong>范型不是类型绑定的所以 List<a> 和 List<b> 不是同一个类可以使用通配符将两个属性变成相同的</b></a></strong></li>
<li><strong>泛型类中的数组对数组的限制 不能实例化泛型数组 其次不能声明 泛型组成的数组</strong></li>
<li><strong>不能实例化范型 new T();</strong></li>
</ul>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/10/09/README/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kyssion">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="kyssion-blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/10/09/README/" itemprop="url">未命名</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-10-09T15:22:37+08:00">
                2018-10-09
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h1 id="我的博库文章"><a href="#我的博库文章" class="headerlink" title="我的博库文章"></a>我的博库文章</h1><hr>
<p>平时一些积累和学习心得都记录在这里。</p>
<p>主要是java golang 一些算法，以后准备扩充人工智能相关的东西。</p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/10/09/GoF设计模式（六）-prototype/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kyssion">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="kyssion-blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/10/09/GoF设计模式（六）-prototype/" itemprop="url">未命名</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-10-09T15:22:37+08:00">
                2018-10-09
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h3 id="原型模式"><a href="#原型模式" class="headerlink" title="原型模式"></a>原型模式</h3><p>原型模式其实本质上解决了如下的两个问题：</p>
<ul>
<li>类名称和类的绑定，无法实现动态的（通过字符串或者名称很方便的）生成想要生成的相关累的实例。</li>
<li>一个统一的入口将相同种类（实现同一个借口或者继承自相同的类的类）进行统一的管理</li>
</ul>
<blockquote>
<p>自我引申： 感觉这个模式，相当于商品的买卖，而圆形模式中的字符串就相当于需要金钱（一种通用的可共识的东西），而产出的类，就相当于商品</p>
</blockquote>
<h3 id="原型模式类图"><a href="#原型模式类图" class="headerlink" title="原型模式类图"></a>原型模式类图</h3><p><img src="blogimg/GAF/6.png" alt=""></p>
<p>根据上面所说的我的理解可以这么类比</p>
<ul>
<li>client 相当于用户</li>
<li>users 的过程相当于付款</li>
<li>prototype的createClone 相当于取货的过程</li>
<li>最后 concretePrototype（prototype） 就是商品</li>
</ul>
<p>通过这样的分析，其实理论上createClone和prototype应该是要解耦的但是，因为java中clone只能自调用所以采用这种方法，其实可以在分装一层调用层，不过这样就增加了复杂度了，这里就不多说了。</p>
<p>方便理解；下面是程序的类图</p>
<p><img src="blogimg/GAF/7.png" alt=""></p>
<h3 id="原型模式例子"><a href="#原型模式例子" class="headerlink" title="原型模式例子"></a>原型模式例子</h3><h4 id="client-的实现"><a href="#client-的实现" class="headerlink" title="client 的实现"></a>client 的实现</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.kys.Gaf.prototype;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Message</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> HashMap&lt;String,Product&gt; showcase =</span><br><span class="line">            <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">register</span><span class="params">(String name,Product o)</span></span>&#123;</span><br><span class="line">        showcase.put(name,o);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> Product <span class="title">create</span><span class="params">(String name)</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> showcase.get(name).createClone();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="商品接口的实现"><a href="#商品接口的实现" class="headerlink" title="商品接口的实现"></a>商品接口的实现</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.kys.Gaf.prototype;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Product</span> <span class="keyword">extends</span> <span class="title">Cloneable</span></span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">use</span><span class="params">(String message)</span></span>;</span><br><span class="line">    <span class="function">Product <span class="title">createClone</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="商品接口的实现类"><a href="#商品接口的实现类" class="headerlink" title="商品接口的实现类"></a>商品接口的实现类</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.kys.Gaf.prototype;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MessageBox</span> <span class="keyword">implements</span> <span class="title">Product</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">char</span> segmentation;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">MessageBox</span><span class="params">(<span class="keyword">char</span> segmentation)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.segmentation = segmentation;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">use</span><span class="params">(String message)</span> </span>&#123;</span><br><span class="line">        printLine(message.length());</span><br><span class="line">        System.out.println(<span class="keyword">this</span>.segmentation + message + <span class="keyword">this</span>.segmentation);</span><br><span class="line">        printLine(message.length());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">printLine</span><span class="params">(<span class="keyword">int</span> length)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> a = <span class="number">0</span>; a &lt; length + <span class="number">2</span>; a++) &#123;</span><br><span class="line">            System.out.print(<span class="keyword">this</span>.segmentation);</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Product <span class="title">createClone</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> (Product) <span class="keyword">this</span>.clone();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (CloneNotSupportedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.kys.Gaf.prototype;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">UnderLinerBox</span> <span class="keyword">implements</span> <span class="title">Product</span></span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">char</span> segmentation;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">UnderLinerBox</span><span class="params">(<span class="keyword">char</span> segmentation)</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.segmentation=segmentation;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">use</span><span class="params">(String message)</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="keyword">this</span>.segmentation+message+<span class="keyword">this</span>.segmentation);</span><br><span class="line">        printLine(message.length());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">printLine</span><span class="params">(<span class="keyword">int</span> length)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> a = <span class="number">0</span>; a &lt; length + <span class="number">2</span>; a++) &#123;</span><br><span class="line">            System.out.print(<span class="keyword">this</span>.segmentation);</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Product <span class="title">createClone</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> (Product) <span class="keyword">this</span>.clone();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (CloneNotSupportedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="主函数"><a href="#主函数" class="headerlink" title="主函数"></a>主函数</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.kys.Gaf.prototype;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Message message = <span class="keyword">new</span> Message();</span><br><span class="line">        Product box1 = <span class="keyword">new</span> MessageBox(<span class="string">'~'</span>);</span><br><span class="line">        Product box2 = <span class="keyword">new</span> MessageBox(<span class="string">'*'</span>);</span><br><span class="line">        Product box3 = <span class="keyword">new</span> UnderLinerBox(<span class="string">'-'</span>);</span><br><span class="line"></span><br><span class="line">        message.register(<span class="string">"~"</span>,box1);</span><br><span class="line">        message.register(<span class="string">"*"</span>,box2);</span><br><span class="line">        message.register(<span class="string">"-"</span>,box3);</span><br><span class="line"></span><br><span class="line">        Product boxx1 = message.create(<span class="string">"~"</span>);</span><br><span class="line">        Product boxx2 = message.create(<span class="string">"*"</span>);</span><br><span class="line">        Product boxx3 = message.create(<span class="string">"-"</span>);</span><br><span class="line"></span><br><span class="line">        System.out.println(box1+<span class="string">" "</span>+boxx1);</span><br><span class="line">        System.out.println(box2+<span class="string">" "</span>+boxx2);</span><br><span class="line">        System.out.println(box3+<span class="string">" "</span>+boxx3);</span><br><span class="line"></span><br><span class="line">        boxx1.use(<span class="string">"hello world"</span>);</span><br><span class="line">        boxx2.use(<span class="string">"hello world"</span>);</span><br><span class="line">        boxx3.use(<span class="string">"hello world"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/10/09/JAVA的SPI和API详解/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kyssion">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="kyssion-blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/10/09/JAVA的SPI和API详解/" itemprop="url">未命名</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-10-09T15:22:37+08:00">
                2018-10-09
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <p>api 机制 好说其实就是定义一个接口然后使用他的一个实现类去进行上转型</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        Myinterface myinterface = <span class="keyword">new</span> MyInterfaceImg();</span><br><span class="line">        myinterface.say();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Myinterface</span></span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">say</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyInterfaceImg</span> <span class="keyword">implements</span>  <span class="title">Myinterface</span></span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">say</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"create now"</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>但是使用spi则是另一种特殊的方法</p>
<p>SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制(使用接口发现他的实现类-ServiceLoader<search> s = ServiceLoader.load(Search.class);)。 目前有不少框架用它来做服务的扩展发现， 简单来说，它就是一种动态替换发现的机制， 举个例子来说， 有个接口，想运行时动态的给它添加实现，你只需要添加一个实现.而后，把新加的实现，描述给JDK知道就行啦（通过改一个文本文件即可） 公司内部，目前Dubbo框架和早期的common.log使用这种方法。</search></p>
<p>使用的结构图如下:</p>
<p>!()[blogimg/1.jpg]</p>
<p>其实使用spi的核心就是这个配置文件,这个配置文件在jar包的路径如下</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">└── META-INF</span><br><span class="line">    └── services</span><br><span class="line">        └── com.kys.接口名称  #配置文件的路径</span><br></pre></td></tr></table></figure>
<p>我们都知道vm使用双亲委派机制的类加载器加载各种类(ClassLoader A -&gt; System class loader -&gt; Extension class loader -&gt; Bootstrap class loader)<br>在spi 中,SPI 接口的代码中使用线程上下文类加载器(使用 ServiceLoader<hellointerface> loaders = ServiceLoader.load(接口名称.class);)，就可以成功的加载到 SPI 实现的类.  </hellointerface></p>
<p>具体的实现见下面的代码</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> &lt;S&gt; <span class="function">ServiceLoader&lt;S&gt; <span class="title">load</span><span class="params">(Class&lt;S&gt; service)</span> </span>&#123;</span><br><span class="line">    ClassLoader cl = Thread.currentThread().getContextClassLoader();</span><br><span class="line">    <span class="keyword">return</span> ServiceLoader.load(service, cl);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>看一个实例</p>
<p>接口:<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.liu.spi;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">IA</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">print</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>三个实现类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.liu.spi;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AIAImpl</span> <span class="keyword">implements</span> <span class="title">IA</span> </span>&#123;</span><br><span class="line"> </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">print</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"AIA"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">package</span> com.liu.spi;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BIAImpl</span> <span class="keyword">implements</span> <span class="title">IA</span></span>&#123;</span><br><span class="line"> </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">print</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"BIA"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">package</span> com.liu.spi;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CIAImpl</span> <span class="keyword">implements</span> <span class="title">IA</span> </span>&#123;</span><br><span class="line"> </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">print</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"CIA"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>META-INF/services/com.liu.spi.IA这个文件的内容(如果使用maven工程构建在 src/main/resources/META-INF/services/com.liu.spi.IA这个目录)</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">com.liu.spi.AIAImpl</span><br><span class="line">com.liu.spi.BIAImpl</span><br><span class="line">com.liu.spi.CIAImpl</span><br></pre></td></tr></table></figure>
<p>运行的主函数</p>
<pre><code class="java"><span class="keyword">package</span> com.liu.spi;
<span class="keyword">import</span> java.util.Iterator;
<span class="keyword">import</span> java.util.ServiceLoader;
<span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">IATest</span> </span>{
    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{
        ServiceLoader&lt;IA&gt; spiLoader = ServiceLoader.load(IA.class); 
        Iterator&lt;IA&gt; iaIterator = spiLoader.iterator(); 
        <span class="keyword">while</span> (iaIterator.hasNext()) { 
            iaIterator.next().print(); 
        } 
    }
}
</code></pre>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
  </section>

  
  <nav class="pagination">
    <a class="extend prev" rel="prev" href="/page/11/"><i class="fa fa-angle-left"></i></a><a class="page-number" href="/">1</a><span class="space">&hellip;</span><a class="page-number" href="/page/11/">11</a><span class="page-number current">12</span><a class="page-number" href="/page/13/">13</a><a class="page-number" href="/page/14/">14</a><a class="extend next" rel="next" href="/page/13/"><i class="fa fa-angle-right"></i></a>
  </nav>



          </div>
          


          

        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      

      <section class="site-overview-wrap sidebar-panel sidebar-panel-active">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <p class="site-author-name" itemprop="name">kyssion</p>
              <p class="site-description motion-element" itemprop="description"></p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/archives/">
              
                  <span class="site-state-item-count">133</span>
                  <span class="site-state-item-name">日志</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-categories">
                
                  <span class="site-state-item-count">3</span>
                  <span class="site-state-item-name">分类</span>
                
              </div>
            

            
              
              
              <div class="site-state-item site-state-tags">
                
                  <span class="site-state-item-count">2</span>
                  <span class="site-state-item-name">标签</span>
                
              </div>
            

          </nav>

          

          

          
          

          
          

          

        </div>
      </section>

      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2018</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">kyssion</span>

  
</div>


  <div class="powered-by">由 <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a> 强力驱动</div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">主题 &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Mist</a> v5.1.4</div>




        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  
    <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.4"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.4"></script>



  
  

  

  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.4"></script>



  


  




	





  





  












  





  

  

  

  
  

  

  

  

</body>
</html>
